package top.cardone.data.jdbc.action

import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder
import com.google.common.base.Charsets
import com.google.common.collect.Lists
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import groovy.sql.Sql
import org.apache.commons.io.FileUtils
import org.apache.commons.lang3.ArrayUtils
import org.apache.commons.lang3.StringUtils
import org.springframework.core.io.Resource
import org.springframework.util.StopWatch
import top.cardone.context.ApplicationContextHolder
import top.cardone.core.util.action.Action0
import top.cardone.data.jdbc.datasource.looku.RoutingDataSource

import java.nio.charset.StandardCharsets

@groovy.util.logging.Log4j2
class ExecuteSqlsAction implements Action0 {
    Resource[] sqlFiles

    String[] dataSourceBeanNames = ["dataSource"]

    String separator = "-- new sql"

    boolean isShowSql = true

    boolean isSkip = false

    List<Action0> actions

    Resource executedSqlsFile

    @Override
    void action() {
        if (isSkip) {
            return
        }

        List<String> executedSqls = null

        try {
            if (executedSqlsFile != null && executedSqlsFile.exists()) {
                executedSqls = ApplicationContextHolder.getBean(Gson.class).fromJson(
                        FileUtils.readFileToString(executedSqlsFile.getFile(), StandardCharsets.UTF_8),
                        new TypeToken<List<String>>() {
                        }.getType())
            }
        } catch (Throwable e) {
            log.error(e)
        }

        if (executedSqls == null) {
            executedSqls = Lists.newArrayList()
        }

        for (String dataSourceBeanName : dataSourceBeanNames) {
            DynamicDataSourceContextHolder.push(dataSourceBeanName)

            Sql sql = ApplicationContextHolder.getBean(Sql.class)

            try {
                if (ArrayUtils.isNotEmpty(sqlFiles)) {
                    for (Resource sqlFile : sqlFiles) {
                        if (!sqlFile.exists()) {
                            continue
                        }

                        String text = FileUtils.readFileToString(sqlFile.getFile(), Charsets.UTF_8)

                        if (StringUtils.isBlank(text)) {
                            continue
                        }

                        String[] executeSqls = text.split(this.separator)

                        for (String executeSql : executeSqls) {
                            if (StringUtils.isBlank(executeSql)) {
                                continue
                            }

                            if (StringUtils.equals(executeSql, "\n")) {
                                continue
                            }

                            if (executedSqls.contains(executeSql)) {
                                continue
                            }

                            def sw = new StopWatch()

                            sw.start(dataSourceBeanName + ":" + executeSql)

                            try {
                                sql.execute(executeSql)

                                executedSqls.add(executeSql)

                                try {
                                    String json = ApplicationContextHolder.getBean(Gson.class).toJson(executedSqls)

                                    FileUtils.writeStringToFile(executedSqlsFile.getFile(), json, Charsets.UTF_8)
                                } catch (Throwable e) {
                                    log.error(e)
                                }
                            } catch (Throwable e) {
                                log.error(e.getMessage())
                            }

                            sw.stop()

                            if (isShowSql) {
                                System.out.println(sw.prettyPrint())
                            }
                        }
                    }
                }

                if (actions) {
                    for (Action0 action : actions) {
                        try {
                            action.action()
                        } catch (Throwable e) {
                            log.error(e.getMessage(), e)
                        }
                    }
                }
            } catch (Throwable e) {
                log.error(e)
            } finally {
                DynamicDataSourceContextHolder.clear()
            }
        }
    }
}
